#pragma once
#include <iostream>
#include <string>
#include <filesystem>
#include <fstream>
#include <memory>
#include <unistd.h>
#include <time.h>
#include <cstdio>
#include "mymutex.hpp"
using namespace std;

namespace my_log
{
    // 首先要实现刷新策略：我们采用继承多态
    enum class LogLevel // 日志的等级
    {
        DEBUG,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    string L_level(LogLevel level)
    {
        switch (level)
        {
        case LogLevel::DEBUG:
            return "DEBUG";
        case LogLevel::INFO:
            return "INFO";
        case LogLevel::WARNING:
            return "WARNING";
        case LogLevel::ERROR:
            return "ERROR";
        case LogLevel::FATAL:
            return "FATAL";
        default:
            return nullptr;
        }
    }
    class LogStrategy // 刷新策略的父类
    {
    public:
        LogStrategy() = default; // 默认形成构造函数
        virtual void SyncLog(const string &messages) = 0;
        ~LogStrategy()
        {
        }

    private:
    };
    class LogConsoleStrategy : public LogStrategy
    {
    public:
        LogConsoleStrategy()
        {
        }
        void SyncLog(const std::string &message) override
        {
            _mutex.lock();
            cout << message << endl;
            _mutex.unlock();
        }
        ~LogConsoleStrategy()
        {
        }

    private:
        my_mutex::mymutex _mutex;
    };
    string defaultpath = "./mylog";
    string defaultname = "log.txt";
    class LogFileStrategy : public LogStrategy
    {
    public:
        LogFileStrategy(string path = defaultpath, string name = defaultname)
            : _path(path), _name(name)
        {
            _mutex.lock();
            // 判断_path是否存在
            if (std::filesystem::exists(_path))
            {
                return; // 存在则返回
            }
            // 不存在则创建_path
            try
            {
                std::filesystem::create_directories(_path);
            }
            catch (const std::filesystem::filesystem_error &e)
            {
                std::cerr << e.what() << '\n';
            }

            file = _path + (_path.back() == '/' ? "" : "/") + _name; // 形成文件
            _mutex.unlock();
        }
        void SyncLog(const std::string &messages) override
        {
            _mutex.lock();
            std::ofstream out(file, std::ios::app); // 追加方式写入
            if (!out.is_open())
            {
                return;
            }
            out << messages << "\r\n";
            out.close();
            _mutex.unlock();
        }
        ~LogFileStrategy()
        {
        }

    private:
        my_mutex::mymutex _mutex;
        string _path;
        string _name;
        string file;
    };
    string gettimestamp()
    {
        const time_t t = time(nullptr);
        struct tm curr_tm;
        localtime_r(&t, &curr_tm);
        char buffer[128];
        snprintf(buffer, sizeof(buffer), "%4d-%02d-%02d %02d:%02d:%02d",
                 curr_tm.tm_year + 1900,
                 curr_tm.tm_mon + 1,
                 curr_tm.tm_mday,
                 curr_tm.tm_hour,
                 curr_tm.tm_min,
                 curr_tm.tm_sec);
        return buffer;
    }
    class Logger
    {
    public:
        Logger()
        {
            ConsoleStrategy(); // 默认使用控制台刷新策略
        }
        void ConsoleStrategy()
        {
            _flush_way = std::make_unique<LogConsoleStrategy>();
        }
        void FileStrategy()
        {
            _flush_way = std::make_unique<LogFileStrategy>();
        }
        // 内部类,形成一条完整的日志
        class LogMessage //  但实际内部类 和 Logger是两个不同的类
        {
        public:
            LogMessage(LogLevel &level, string &src_name, int line, Logger &logger)
                : _time(gettimestamp()), _level(level), _pid(getpid()), _src_name(src_name), _line(line), _logger(logger)
            {
                // 形成日志的左半部分
                std::stringstream ss;
                ss << '[' << time << ']'
                   << '[' << L_level(_level) << ']'
                   << '[' << _pid << ']'
                   << '[' << _src_name << ']'
                   << '[' << line << ']';
                _log = ss.str();
                _log += '-';
            }
            template <typename T>
            // 重载<<
            LogMessage &operator<<(T messages)//稍等我在看一下
            {
                std::stringstream ss;
                ss << messages;
                _log += ss.str();
                return *this;
            }
            ~LogMessage()
            {
                // 析构函数调用,自动刷新日志内容
                _logger._flush_way->SyncLog(_log);
            }

        private:
            string _time;
            LogLevel _level;
            pid_t _pid;
            string _src_name; // 文件名字
            int _line;        // 行号
            string _log;      // 合并好的日志信息
            Logger &_logger;  // 调用析构函数的时候进行刷新日志
        };
        LogMessage operator()(LogLevel level, string name, int line)
        {
            return LogMessage(level, name, line, *this);
        }

    private:
        std::unique_ptr<LogStrategy> _flush_way;
    };
    Logger l;  //你的l是Logger的对象
#define LOG(level) l(level, __FILE__, __LINE__)
}